<?php
//商城下单处理模块
namespace extend;

use lib\AppStore\AppList;
use lib\Hook\Hook;
use lib\Pay\Pay;
use lib\supply\Order;
use lib\supply\Price;
use login_data;
use Medoo\DB\SQL;

class Buy
{

    public static $User; //用户信息

    /**
     * @param $Gid
     * @param $num
     * @param $InputData //下单信息
     * @param $User //用户信息
     * @param $DataRequest //用户提交的参数
     * @return array
     * 验证订单是否可以购买，并且返回商品数据
     */
    public static function Verify($Gid, $num, $InputData, $User = false, $DataRequest = [])
    {
        global $conf, $times, $date;
        self::$User = (!$User['id'] ? false : $User); //初始化赋值

        //用户禁封验证
        if (self::$User && (int)$User['state'] !== 1) {
            return array('code' => -1, 'msg' => '当前账号已被禁封，无法购买商品！');
        }
        $DB = SQL::DB();
        $Goods = $DB->get('goods', '*', ['gid' => (int)$Gid]);
        if (!$Goods) {
            return ['code' => -1, 'msg' => '商品不存在'];
        }
        if ($Goods['state'] != 1) {
            return ['code' => -1, 'msg' => '商品已下架'];
        }

        //下单份数修正
        if ($num < 1 || !in_array(7, json_decode($Goods['method'], TRUE))) {
            $num = 1;
        }
        //验证下单信息是否存在违禁词
        $arr_blacklist = explode(',', $conf['blacklist']);
        $idd = 1;
        foreach ($InputData as $key => $v) {
            if (empty($v)) {
                return array('code' => -1, 'msg' => '请将第' . trim($idd) . '行输入框填写完整！');
            }
            $InputData[$key] = $v;
            ++$idd;
        }
        foreach ($arr_blacklist as $v) {
            if (empty($v)) {
                continue;
            }
            if (strpos(json_encode($InputData), $v) !== false) {
                return array('code' => -1, 'msg' => '下单信息：' . $v . ' 已被站长设置为下单违禁词！');
            }
        }

        //验证下单信息是否存在错误
        $inputCount = 0;
        if ((int)$Goods['specification'] === 2) {
            $SpRule = RlueAnalysis($Goods, 1, $User);
            $SkuData = [
                'data' => $SpRule,
                'SPU' => json_decode($Goods['specification_spu'], TRUE),
            ];
            $KeyName = [];
            $SpuIn = 0; //初始化
            $InputArr = [];
            foreach ($SkuData['SPU'] as $val) {
                ++$inputCount;
                $input = $InputData[$SpuIn];
                foreach ($InputData as $v) {
                    if (in_array($v, $val)) {
                        $input = $v;
                    }
                }
                $InputArr[$SpuIn] = $input;
                ++$SpuIn;
            }
            $InputDataArray = $InputData;
            foreach ($InputArr as $k => $v) {
                $InputDataArray[$k] = $v;
                $KeyName[] = $v;
            }
            $InputData = $InputDataArray;
            $DataRule = $SkuData['data']['Parameter'][implode('`', $KeyName)];
            if (empty($DataRule)) {
                return array('code' => -1, 'msg' => '商品规格选择错误,请选择正确的参数!');
            }
            $Goods = array_merge($Goods, $DataRule);
        } else {
            $Pricer = Price::Get($Goods['money'], $Goods['profits'], ($User === false ? 1 : $User['grade']), $Goods['gid'], $Goods['selling'], $Goods['profit_rule']);
            $Goods['price'] = $Pricer['price'];
            $Goods['points'] = $Pricer['points'];
        }

        $InputArrs = explode('|', $Goods['input']);
        if (empty($Goods['input'])) {
            $InputArrs = [];
        }
        if (count($InputArrs) === 1 && $inputCount === 0) {
            $inputCount += 1;
        } else if (!empty($Goods['input'])) {
            $inputCount += count($InputArrs);
        }
        if ($inputCount != count($InputData)) {
            return array('code' => -1, 'msg' => '商品下单信息错误,请检查下单信息是否正确!');
        }

        //验证付款方式是否支持
        if (count($DataRequest) >= 1) {
            //付款方式
            $PayType = (int)$DataRequest['type'] ?? 1; //1=在线支付，2=余额付款，3=积分兑换，4=免费，5=直接下单

            //验证免费商品
            if ($Goods['price'] <= 0 || $Goods['points'] <= 0) {
                //有一个是0就是免费商品
                if (self::$User === false && $conf['tourist_add'] != 1) {
                    return array('code' => -1, 'msg' => '请先登录后再购买免费商品!');
                }
                $num = 1; //如果是免费，购买份数必定为1
                $PayType = 4;
            }
            //验证余额商品
            if ($PayType == 2) {
                if (self::$User === false) {
                    return array('code' => -1, 'msg' => '使用余额下单需要先登录!');
                }
            }

            //验证积分商品
            if ($PayType == 3) {
                if (self::$User === false) {
                    return array('code' => -1, 'msg' => '使用积分下单需要先登录!');
                }
            }
            //验证付款方式[商品级]
            $methods = json_decode($Goods['method'], true);
            if ($PayType === 2 && !in_array(2, $methods)) {
                return array('code' => -1, 'msg' => '此商品不支持使用余额购买！');
            } else if ($PayType === 3 && !in_array(3, $methods)) {
                return array('code' => -1, 'msg' => '此商品不支持使用积分兑换！');
            } else if ($PayType == 1 && !in_array(1, $methods)) {
                return array('code' => -1, 'msg' => '此商品不支持使用在线付款购买！');
            }
            //判断下单方式是否支持[分类级]
            $Class = $DB->get('class', ['support'], [
                'cid' => (int)$Goods['cid']
            ]);
            if ($Class) {
                $support = explode(',', $Class['support']);
                if ($PayType === 2 && $support[3] != 1) {
                    return array('code' => -1, 'msg' => '此商品不支持使用余额购买！');
                } else if ($PayType === 3 && $support[4] != 1) {
                    return array('code' => -1, 'msg' => '此商品不支持使用积分兑换！');
                }
                if ($PayType == 1) {
                    switch ($DataRequest['mode']) {
                        case 'qqpay':
                            if ($support[0] == 2) {
                                return array('code' => -1, 'msg' => '此商品不支持使用QQ钱包购买！');
                            }
                            break;
                        case 'wxpay':
                            if ($support[1] == 2) {
                                return array('code' => -1, 'msg' => '此商品不支持使用微信购买！');
                            }
                            break;
                        case 'alipay':
                            if ($support[2] == 2) {
                                return array('code' => -1, 'msg' => '此商品不支持使用支付宝购买！');
                            }
                            break;
                    }
                }
            }

            //验证下单方式的限购方案
            if ($PayType == 3 || $PayType == 4) {
                if ($conf['tourist_add'] != 1) {
                    $Day = $DB->count('journal', [
                        'name' => ['积分兑换', '免费领取'],
                        'uid' => $User['id'],
                        'date[>]' => $times,
                    ]);
                    if ($Day > (int)$conf['getinreturn']) {
                        return array('code' => -1, 'msg' => '您今日可领取或兑换商品次数已达上限,请明天再来或看看其他付费商品,次日0点更新购买额度！,您今日最多可领取或兑换' . $conf['getinreturn'] . '次商品！');
                    }
                    $Day = $DB->count('journal', [
                        'name' => ['积分兑换', '免费领取'],
                        'date[>]' => $times,
                    ]);
                    if ($Day > (int)$conf['getinreturn_all']) {
                        return array('code' => -1, 'msg' => '本站今日可免费领取或兑换的商品额度已经耗尽,请明天再来或看看其他付费商品,次日0点刷新额度！,本站今日提供了' . $conf['getinreturn_all'] . '次商品领取/兑换次数！');
                    }
                } else {
                    $Day = $DB->count('journal', [
                        'name' => ['积分兑换', '免费领取'],
                        'ip' => userip(),
                        'date[~]' => date('Y-m-d'),
                    ]);
                    if ($Day > (int)$conf['tourist_addnum']) {
                        return array('code' => -1, 'msg' => '您今日可领取或兑换商品次数已达上限,请明天再来或看看其他付费商品,次日0点更新购买额度！,您今日最多可领取或兑换' . $conf['tourist_add'] . '次商品！');
                    }
                }
            }
        }

        //验证下单份数限制
        if ((int)$Goods['min'] <= 0) {
            $Goods['min'] = 1;
        }
        if ((int)$Goods['max'] <= 0) {
            $Goods['max'] = 9999999;
        }
        if ((int)$Goods['min'] > $num) {
            return array('code' => -1, 'msg' => '当前商品最低购买' . $Goods['min'] . '份！');
        }
        if ($num > (int)$Goods['max']) {
            return array('code' => -1, 'msg' => '当前商品最多购买' . $Goods['max'] . '份！');
        }
        $Goods['num'] = $num;

        //验证商品库存
        if ((int)$Goods['deliver'] === 3) {
            $Goods['quota'] = GetCardStock($Gid);
            if ($Goods['quota'] < $num) {
                return ['code' => -1, 'msg' => '商品库存不足' . $num . '份'];
            }
        } else if ((int)$Goods['quota'] <= 0) {
            return ['code' => -1, 'msg' => '商品库存不足'];
        } else if ((int)$Goods['quota'] < $num) {
            return ['code' => -1, 'msg' => '商品库存不足' . $num . '份'];
        }

        //商品打折活动计算
        $Seckill = $DB->get('seckill', '*', [
            'end_time[>]' => $date,
            'start_time[<]' => $date,
            'gid' => (int)$Gid
        ]);
        if ($Seckill) {
            $attend = $DB->count('order', [
                'gid' => $Gid,
                'addtitm[>]' => $Seckill['start_time'],
                'addtitm[<]' => $Seckill['end_time']
            ]) - 0;
            if ($attend < $Seckill['astrict']) {
                $Seckill = $Seckill['depreciate'] - 0;
                $Goods['price'] -= $Goods['price'] * ($Seckill / 100);
                $Goods['points'] -= $Goods['points'] * ($Seckill / 100);
                $Goods['Seckill'] = $Seckill;
            } else {
                $Goods['Seckill'] = -1;
            }
        } else {
            $Goods['Seckill'] = -1;
        }
        return ['code' => 1, 'msg' => '商品信息获取成功！', 'data' => $Goods];
    }

    /**
     * @param $Goods
     * @param $DataBuy
     * @param bool $User
     * 计算订单价格
     */
    public static function Price($Goods, $DataBuy, $User = false)
    {
        global $times, $conf;
        if (!$User) {
            $User = self::$User;
        }
        //价格计算
        $DB = SQL::DB();

        $Money = (float)$Goods['money']; //成本
        $Price = $Goods['price'] * $Goods['num']; //售价
        $Points = $Goods['points'] * $Goods['num']; //积分

        $freight = 0; //运费加价金额
        if ($Goods['freight'] != -1) {
            $Fre = $DB->get('freight', '*', [
                'id' => $Goods['freight'],
                'LIMIT' => 1,
            ]);
            if ($Fre) {
                $freight = Price::Freight($Fre, $DataBuy['data'], $Goods['price'], $Goods['num']);
                $freight -= $Price;
            }
        }

        //倍数加价
        $InputArr = [];
        foreach (explode('|', $Goods['input']) as $key => $value) {
            if (strstr($value, '{') && strstr($value, '}')) {
                $InputArr[$key] = false;
            } else {
                $InputArr[$key] = AppList::MatchingInput($value);
                if ($InputArr[$key]['type'] == 3) {
                    $Multiple = (int)$InputArr[$key]['num']; //需要加价的倍数
                    $Num = ($DataBuy['data'][$key] - 0) ?? 1; //用户输入的倍数
                    $MultipleNum = $Num * $Multiple;
                    //赋予倍数价格
                    $Money = $Goods['money'] * $MultipleNum;
                    $Price *= $MultipleNum;
                    $Points *= $MultipleNum;
                }
            }
        }

        //运费加价
        $Price += $freight;
        $Price = round($Price, 8);

        $Goods['price'] = $Price;
        $Goods['points'] = $Points;
        $Goods['money'] = $Money;

        //获取优惠券ID
        if (!empty($DataBuy['CouponId']) && $DataBuy['CouponId'] == -2 && $User['id'] >= 1 && ($DataBuy['type'] == 1 || $DataBuy['type'] == 2)) {
            $PirceCou = $Price;
            $CouponList = $DB->select('coupon', '*', [
                'OR' => [
                    'apply' => 3,
                    'gid' => $Goods['gid'],
                    'cid' => $Goods['cid'],
                ],
                'oid' => -1,
                'uid' => $User['id'],
            ]);
            $Coupon = [];
            $CouponId = -1;
            foreach ($CouponList as $v) {
                if ($v['term_type'] == 1) {
                    $TIME = strtotime($v['gettime']) + (60 * 60 * 24 * $v['indate']);
                } else {
                    $TIME = strtotime($v['expirydate']);
                }
                if (time() > $TIME) continue;
                switch ($v['type']) {
                    case 2:
                    case 1:
                        $PriceCou = $PirceCou - $v['money'];
                        break;
                    case 3:
                        $PriceCou = ($PirceCou * ($v['money'] / 100));
                        break;
                }

                $CSQL = [
                    'uid' => $User['id'],
                    'oid[!]' => -1,
                    'endtime[>]' => $times
                ];
                if ($conf['CouponUseIpType'] == 1) {
                    $CSQL = [
                        'OR' => [
                            'uid' => $User['id'],
                            'ip' => userip(),
                        ],
                        'oid[!]' => -1,
                        'endtime[>]' => $times
                    ];
                }
                $Count = $DB->count('coupon', $CSQL);
                if ($Count >= $conf['CouponUsableMax']) {
                    continue;
                }

                if ($conf['CouponMinimumType'] == 1) {
                    if ($PriceCou <= ($Goods['money'] * $Goods['num'])) {
                        $PriceCou = ($Goods['money'] * $Goods['num']);
                    }
                } else {
                    if ($PriceCou <= 0) {
                        $PriceCou = 0;
                    }
                }
                $Coupon[] = [
                    'id' => $v['id'],
                    'Price' => round($PriceCou, 2),
                ];
            }

            if (count($Coupon) >= 1) {
                $Coupon = array_sort($Coupon, 'Price');
                $DataBuy['CouponId'] = $Coupon[0]['id'];
            } else {
                $DataBuy['CouponId'] = -1;
            }
        } else {
            $CouponId = $DataBuy['CouponId'];
        }

        //计算使用优惠券后的价格
        /**
         * 验证优惠券！
         */
        if ((int)$CouponId >= 1 && $User['id'] >= 1) {
            $Coupon = $DB->get('coupon', '*', ['id' => (int)$CouponId, 'uid' => (int)$User['id'], 'oid' => -1]);
            if (!$Coupon) {
                return [
                    'code' => -1,
                    'msg' => '优惠券不存在或未绑定到您的账户下,或已经使用！'
                ];
            }
            switch ($Coupon['apply']) {
                case 1:
                    if ($Goods['gid'] != $Coupon['gid']) {
                        return [
                            'code' => -1,
                            'msg' => '此券不能用于此商品！'
                        ];
                    }
                    break;
                case 2:
                    if ($Goods['cid'] != $Coupon['cid']) {
                        return [
                            'code' => -1,
                            'msg' => '此券不能用于此商品！'
                        ];
                    }
                    break;
            }

            if ($Coupon['term_type'] == 1) {
                $TIME = strtotime($Coupon['gettime']) + (60 * 60 * 24 * $Coupon['indate']);
            } else {
                $TIME = strtotime($Coupon['expirydate']);
            }
            if (time() > $TIME) {
                return [
                    'code' => -1,
                    'msg' => '此优惠券已过期！'
                ];
            }

            $CSQL = [
                'uid' => $User['id'],
                'oid[!]' => -1,
                'endtime[>]' => $times
            ];
            if ($conf['CouponUseIpType'] == 1) {
                $CSQL = [
                    'OR' => [
                        'uid' => $User['id'],
                        'ip' => userip(),
                    ],
                    'oid[!]' => -1,
                    'endtime[>]' => $times
                ];
            }
            $CountCoupon = $DB->count('coupon', $CSQL);
            if ($CountCoupon >= $conf['CouponUsableMax']) {
                return [
                    'code' => -1,
                    'msg' => '每天最多可使用' . $conf['CouponUsableMax'] . '张优惠券,今日已经使用了' . $CountCoupon . '张！'
                ];
            }


            switch ($Coupon['type']) {
                case 1:
                    if ($Coupon['minimum'] > $Price) {
                        return [
                            'code' => -1,
                            'msg' => '此优惠券订单付款金额需满' . $Coupon['minimum'] . '元才可使用！'
                        ];
                    }
                    $PriceCou = $Price - $Coupon['money'];
                    break;
                case 2:
                    $PriceCou = $Price - $Coupon['money'];
                    break;
                case 3:
                    if ($Coupon['minimum'] > $Price) {
                        return [
                            'code' => -1,
                            'msg' => '此优惠券订单付款金额需满' . $Coupon['minimum'] . '元才可使用！'
                        ];
                    }
                    $PriceCou = ($Price * ($Coupon['money'] / 100));
                    break;
            }

            if ($conf['CouponMinimumType'] == 1) {
                if ($PriceCou <= ($Money * $DataBuy['num'])) {
                    $PriceCou = ($Money * $DataBuy['num']);
                }
            } else {
                if ($PriceCou <= 0) {
                    $PriceCou = 0;
                }
            }
            $original_price = $Price;
            $Price = $PriceCou;
        } else {
            $original_price = -1;
        }

        //付款方式判断
        if ($DataBuy['type'] == 1) {
            if ($DataBuy['mode'] == 'qqpay') {
                $Mode = 1;
            } else if ($DataBuy['mode'] == 'wxpay') {
                $Mode = 2;
            } else {
                $Mode = 3;
            }
        } else if ($DataBuy['type'] == 2) {
            $Mode = 4;
        } else {
            $Mode = 5;
        }
        //改价操作
        $ChangOp = [
            'Price' => $Price,
            'Points' => $Points,
            'Money' => $Money * $Goods['num'],
            'Data' => $DataBuy['data'],
            'Gid' => $DataBuy['gid'],
            'Uid' => (!$User ? -1 : ($User['id'] - 0)),
            'Num' => $Goods['num'],
            'Mode' => $Mode,
        ];
        //正常付款，改价
        $ChangOp['Type'] = 2;
        $PriceData = ChangOrderPrice($ChangOp);
        $Price = $PriceData['Price'];
        $Points = $PriceData['Points'];
        $Goods['price'] = (float)$Price;
        $Goods['points'] = (float)$Points;
        $Goods['CouponId'] = $CouponId;
        $Goods['original_price'] = $original_price; //原价[如果是-1则未使用优惠券]
        unset($PriceData);
        $free = -1; //是否是免费商品
        switch ($DataBuy['type']) {
            case 2:
                if ($Price <= 0) {
                    $free = 1;
                }
                break;
            case 3:
                if ($Points <= 0) {
                    $free = 1;
                }
                break;
            default:
                if ($Price <= 0 && $conf['tourist_add'] == 1) {
                    $free = 1;
                }
                break;
        }
        $Goods['free'] = $free; //1免费商品，-1不是免费商品

        return [
            'code' => 1,
            'msg' => '价格计算成功',
            'data' => $Goods
        ];
    }


    /**
     * 根据订单编号和商品ID获取待付款订单数据
     */
    public static function OrderGet($gid, $OrderNumber)
    {
        $File = ROOT . '/includes/extend/log/Order/' . $gid . '/' . $OrderNumber . '.json';
        if (!file_exists($File)) {
            return [
                'code' => -1,
                'msg' => '待付款订单不存在！'
            ];
        }
        $OrderData = json_decode(file_get_contents($File), true);
        if (!$OrderData) {
            return [
                'code' => -1,
                'msg' => '订单数据异常！'
            ];
        }
        $OrderData['input'] = json_decode($OrderData['input'], true);
        return [
            'code' => 1,
            'msg' => '订单数据获取成功！',
            'data' => $OrderData
        ];
    }

    /**
     * 创建待付款订单
     * 需要提供：
     * $gid //商品ID
     * $input //下单信息
     * $type //付款类型
     * $mode //付款方式
     * $mode //购买份数
     * @return array
     */
    public static function Create($Goods, $DataBuy)
    {
        //待付款订单生成
        /**
         * 创建临时订单数据，根据商品ID来区分目录，如果想付款则验证订单库存，库存不足直接拦截
         */
        $OrderNumber = date('YmdHis') . rand(11111, 99999); //订单号
        mkdirs(ROOT . '/includes/extend/log/Order/' . $Goods['gid'] . '/'); //创建订单目录
        $File = ROOT . '/includes/extend/log/Order/' . $Goods['gid'] . '/' . $OrderNumber . '.json';
        $uid = -1;
        if (self::$User) {
            $uid = self::$User['id'];
        }
        $Data = [ //订单数据
            'order' => $OrderNumber, //商品订单号
            'uid' => $uid, //用户ID
            'ip' => userip(),
            'input' => json_encode($DataBuy['data'], JSON_UNESCAPED_UNICODE), //下单信息
            'num' => $Goods['num'],
            'gid' => $Goods['gid'],
            'price' => [
                'price' => $Goods['price'], //商品售价
                'points' => $Goods['points'], //积分兑换价格
            ],
            'money' => $Goods['money'] * $Goods['num'], //本单成本
            'coupon' => $Goods['CouponId'], //优惠券ID
            'Seckill' => $Goods['Seckill'], //秒杀ID
            'name' => $Goods['name'], //商品名称
            'quantity' => $Goods['quantity'], //购买数量
            'docs' => $Goods['docs'], //商品说明
            'units' => $Goods['units'], //数量单位
            'type' => $DataBuy['type'], //付款方式
            'mode' => $DataBuy['mode'], //在线支付付款类型
            'original_price' => $Goods['original_price'], //原价[如果是-1则未使用优惠券]
            'free' => $Goods['free'], //是否是免费商品，1免费商品，-1不是免费商品
        ];
        $Json = json_encode($Data, JSON_UNESCAPED_UNICODE);
        if (!file_put_contents($File, $Json)) {
            return [
                'code' => -1,
                'msg' => '订单创建失败！'
            ];
        }

        //写入钩子
        Hook::execute('OrderCache', $Data);

        return [
            'code' => 1,
            'msg' => '订单创建成功！',
            'data' => $Data,
        ];
    }

    /**
     * @param $gid //商品ID
     * @param $InputData //下单信息
     * 获取商品库存
     */
    public static function GetStock($Gid, $InputData)
    {
        if (!is_array($InputData)) {
            $InputData = json_decode($InputData, true);
        }
        $DB = SQL::DB();
        $Goods = $DB->get('goods', '*', ['gid' => $Gid]);
        $inputCount = 0;
        if ((int)$Goods['specification'] === 2) {
            $SpRule = RlueAnalysis($Goods, 1, self::$User);
            $SkuData = [
                'data' => $SpRule,
                'SPU' => json_decode($Goods['specification_spu'], TRUE),
            ];
            $KeyName = [];
            $SpuIn = 0; //初始化
            $InputArr = [];
            foreach ($SkuData['SPU'] as $val) {
                ++$inputCount;
                $input = $InputData[$SpuIn];
                foreach ($InputData as $v) {
                    if (in_array($v, $val)) {
                        $input = $v;
                    }
                }
                $InputArr[$SpuIn] = $input;
                ++$SpuIn;
            }

            $InputDataArray = $InputData;
            foreach ($InputArr as $k => $v) {
                $InputDataArray[$k] = $v;
                $KeyName[] = $v;
            }
            $DataRule = $SkuData['data']['Parameter'][implode('`', $KeyName)];
            if (empty($DataRule)) {
                return [
                    'code' => -1, 'msg' => '商品下单信息有误，无法匹配商品规格！',
                    'count' => $Goods['quota'],
                    'units' => $Goods['units'],
                ];
            }
            $Goods = array_merge($Goods, $DataRule);
        }

        if ((int)$Goods['deliver'] === 3) {
            $Goods['quota'] = GetCardStock($Gid);
        }
        return [
            'code' => 1,
            'msg' => '商品库存获取成功',
            'count' => $Goods['quota'],
            'units' => $Goods['units'],
        ];
    }

    /**
     * @param $order //订单编号
     * @param $gid //商品ID
     * @param $type //1=正常付款，2=无需付款[免费商品]，3=无需付款[无免费付款日志]，4=在线支付订单
     * 处理订单付款，以及库存验证
     */
    public static function Pay($order, $gid, $type = 1)
    {
        global $conf, $date;
        //获取待付款订单数据
        $OrderData = self::OrderGet($gid, $order);
        if ($OrderData['code'] != 1) {
            return $OrderData;
        }
        $OrderData = $OrderData['data'];
        //开始验证订单库存
        $GetStock = self::GetStock($gid, $OrderData['input']);
        if ($GetStock['code'] != 1) {
            return $GetStock;
        }
        $Stock = $GetStock['count']; //商品库存数量[实时]
        if ($Stock < $OrderData['num']) {
            return [
                'code' => -1,
                'msg' => '商品库存不足' . $OrderData['num'] . '份，当前库存为' . $Stock . '份！'
            ];
        }
        //开始验证当前订单是否是重复订单
        $DB = SQL::DB();
        $Date = date('Y-m-d H:i:s', time() - $conf['OrderAstrict']);
        $Order = $DB->get('order', ['addtitm'], [
            'gid' => $gid,
            'uid' => $OrderData['uid'],
            'ip' => $OrderData['ip'],
            'num' => $OrderData['num'],
            'input' => json_encode($OrderData['input'], JSON_UNESCAPED_UNICODE),
            'addtitm[>]' => $Date,
        ]);
        if ($Order) {
            //拦截订单
            return [
                'code' => -1,
                'msg' => '您的订单已被拦截，此商品无法在' . $conf['OrderAstrict'] . '秒内重复下单，请于' . TimeLag($Date, $Order['addtitm']) . '秒后再试！'
            ];
        }

        //判断是否是免费商品
        if ($OrderData['free'] == 1 || $type != 1) {
            //写入免费日志
            if ($type != 3) {
                Hook::execute('PayPoints', [
                    'cause' => '领取了商品' . $OrderData['name'],
                    'uid' => $OrderData['uid'],
                ]);
                userlog('免费领取', '用户[' . $OrderData['uid'] . ']在' . $date . '免费领取了商品[' . $OrderData['name'] . ']！', $OrderData['uid']);
            }
            return [
                'code' => 1,
                'msg' => '免费商品无需付款',
                'payment' => '免费领取',
            ];
        }
        //开始付款
        switch ($OrderData['type']) {
            case 1: //在线支付[请求拦截,付款完成后直接发货]
                Pay::FoundOrder($OrderData);
            case 2: //余额付款
                return self::BalancePay($OrderData);
            case 3: //积分付款
                return self::IntegralPay($OrderData);
            default:
                return [
                    'code' => 1,
                    'msg' => '无需付款,已跳过！',
                    'payment' => '无需付款',
                ];
        }
    }

    /**
     * @param $OrderData
     * @return array
     * 余额付款
     */
    public static function BalancePay($OrderData)
    {
        if ($OrderData['uid'] == -1) {
            return [
                'code' => -1,
                'msg' => '请先登录！'
            ];
        }
        $Price = round($OrderData['price']['price'], 8);
        $DB = SQL::DB();
        $User = $DB->get('user', '*', ['id' => $OrderData['uid']]);
        if (!$User || $User['state'] != 1) {
            return [
                'code' => -1,
                'msg' => '用户不存在或已被封禁！'
            ];
        }
        if ($User['money'] < $Price) {
            return [
                'code' => -1,
                'msg' => '您的账户余额不足，无法完成购买！'
            ];
        }
        if (($User['money'] - $Price) < 0) {
            return [
                'code' => -1,
                'msg' => '账户数据异常，无法完成购买，请先去充值！'
            ];
        }
        //开始扣款
        $Res = $DB->update('user', [
            'money[-]' => $Price
        ], [
            'id' => $OrderData['uid']
        ]);
        if ($Res) {
            Hook::execute('PayMoney', [
                'cause' => '余额支付,购买了商品' . $OrderData['name'] . ',付款金额为：' . $Price . '元',
                'money' => $OrderData['price']['price'],
                'uid' => $User['id'],
            ]);
            global $date;
            userlog('余额购买', '用户[' . $User['id'] . ']在' . $date . '用' . $Price . '元余额购买了商品[' . $OrderData['name'] . ']！' . login_data::pushMsg($Price, 2), $User['id'], $Price);
            return [
                'code' => 1,
                'msg' => '付款成功！',
                'payment' => '余额付款',
            ];
        }
        return [
            'code' => -1,
            'msg' => '付款失败！'
        ];
    }

    /**
     * @param $OrderData
     * 积分付款
     */
    public static function IntegralPay($OrderData)
    {
        global $conf, $date;

        if ($conf['IntegratingSwitch'] != 1) {
            return [
                'code' => -1,
                'msg' => '当前站点已关闭积分兑换功能，请使用其他付款方式购买！'
            ];
        }

        if ($OrderData['uid'] == -1) {
            return [
                'code' => -1,
                'msg' => '请先登录！'
            ];
        }
        $Price = round($OrderData['price']['points'], 8);
        $DB = SQL::DB();
        $User = $DB->get('user', '*', ['id' => $OrderData['uid']]);
        if (!$User || $User['state'] != 1) {
            return [
                'code' => -1,
                'msg' => '用户不存在或已被封禁！'
            ];
        }
        if ($User['currency'] < $Price) {
            return [
                'code' => -1,
                'msg' => '您的账户' . $conf['currency'] . '不足，无法完成购买！'
            ];
        }
        if (($User['currency'] - $Price) < 0) {
            return [
                'code' => -1,
                'msg' => '账户数据异常，无法完成购买！'
            ];
        }
        //开始扣款
        $Res = $DB->update('user', [
            'currency[-]' => $Price
        ], [
            'id' => $OrderData['uid']
        ]);
        if ($Res) {
            Hook::execute('PayPoints', [
                'cause' => '兑换了商品' . $OrderData['name'] . ',消耗了' . $Price . $conf['currency'],
                'money' => $Price,
                'uid' => $User['id'],
            ]);
            userlog('积分兑换', '用户[' . $User['id'] . ']在' . $date . '用' . $Price . $conf['currency'] . '兑换了商品[' . $OrderData['name'] . ']！', $User['id'], $Price);
            return [
                'code' => 1,
                'msg' => '兑换成功！',
                'payment' => '积分兑换',
            ];
        }
        return [
            'code' => -1,
            'msg' => '付款失败！'
        ];
    }

    /**
     * @param $gid //商品ID
     * @param $order //待付款订单编号
     * @param $payment //付款方式
     * @param $trade_no //付款订单号
     * @return array
     * 创建商品订单
     */
    public static function CreateOrder($gid, $order, $payment = '余额付款', $trade_no = '此付款方式无对接订单号')
    {
        global $date;
        $OrderData = self::OrderGet($gid, $order);
        if ($OrderData['code'] != 1) {
            return $OrderData;
        }
        $OrderData = $OrderData['data'];
        $DB = SQL::DB();
        $Price = ($OrderData['type'] != 3 ? $OrderData['price']['price'] : $OrderData['price']['points']);
        $Uty = UserConf::judge(null, $OrderData['order']);
        $SQL = [
            'order' => $OrderData['order'],
            'trade_no' => $trade_no,
            'uid' => $OrderData['uid'],
            'muid' => (!$Uty ? -1 : $Uty['id']),
            'name' => $OrderData['name'], //商品名称
            'docs' => $OrderData['docs'], //商品说明
            'quantity' => $OrderData['quantity'], //购买数量
            'units' => $OrderData['units'], //数量单位
            'ip' => $OrderData['ip'],
            'input' => json_encode($OrderData['input'], JSON_UNESCAPED_UNICODE),
            'state' => 2, //待处理状态
            'num' => $OrderData['num'],
            'return' => '订单创建成功！', //此刻尚未处理完订单
            'gid' => $OrderData['gid'],
            'money' => $OrderData['money'],
            'originalprice' => $OrderData['original_price'], //原价
            'coupon' => $OrderData['coupon'], //优惠券ID
            'payment' => $payment,
            'price' => $Price, //获取实际付款金额
            'docking' => 3, //处于未对接状态
            'addtitm' => $date,
        ];
        $Order = $DB->insert('order', $SQL);
        $ID = $DB->id();
        if ($Order) {
            $Goods = $DB->get('goods', '*', ['gid' => $OrderData['gid']]);
            //减少商品库存
            Order::ReduceStocks($Goods, $OrderData['num'], $ID, $OrderData['input']);
            //调整优惠券状态
            if ($OrderData['coupon'] != -1) {
                $CouponRes = $DB->update('coupon', [
                    'oid' => $ID,
                    'ip' => userip(),
                    'endtime' => $date,
                ], [
                    'id' => $OrderData['coupon']
                ]);
                userlog('使用优惠券', '用户[' . $OrderData['uid'] . ']使用优惠券[' . $OrderData['coupon'] . ']购买了商品[' . $OrderData['name'] . ']！,商品原价[' . round($OrderData['original_price'], 8) . '元],优惠后价格为[' . round($Price, 8) . '元],共优惠[' . round($OrderData['original_price'] - $Price, 8) . '元],优惠券使用后若订单退款不退还！', $OrderData['uid'], round($OrderData['original_price'] - $Price, 8));
                if (!$CouponRes) {
                    //保险措施，优惠券状态调整失败，直接删除
                    $DB->delete('coupon', ['id' => $OrderData['coupon']]);
                }
            }
            Hook::execute('OrderAdd', $SQL);

            mkdirs(SYSTEM_ROOT . 'extend/log/OrderQuery/');
            foreach ($OrderData['input'] as $value) {
                if (is_url($value)) {
                    $url = URLExtraction($value);
                    if (!$url != $value) {
                        file_put_contents(SYSTEM_ROOT . 'extend/log/OrderQuery/' . md5($url) . '.' . $ID, $ID);
                    }
                }
                file_put_contents(SYSTEM_ROOT . 'extend/log/OrderQuery/' . md5($value) . '.' . $ID, $ID);
            }
            return [
                'code' => 1,
                'msg' => '订单创建成功',
                'data' => [
                    'id' => $ID, //订单ID
                    'order' => $OrderData['order'], //订单号
                ]
            ];
        }

        return [
            'code' => -1,
            'msg' => '订单创建失败'
        ];
    }


    //订单发货
    public static function Delivery($id)
    {
        $DB = SQL::DB();
        $Order = $DB->get('order', '*', ['id' => $id]);
        if (!$Order) {
            return [
                'code' => -1,
                'msg' => '订单不存在！'
            ];
        }
        $Goods = $DB->get('goods', '*', ['gid' => $Order['gid']]);
        $Goods['num'] = $Order['num'];
        if (Order::OrderSubmit([
            'id' => $id,
            'order' => $Order['order'],
        ], $Goods)) {
            //清除待付款订单文件缓存
            $File = ROOT . '/includes/extend/log/Order/' . $Goods['gid'] . '/' . $Order['order'] . '.json';
            if (is_file($File)) {
                unlink($File);
            }
        }
        return [
            'code' => 1,
            'msg' => '商品订单创建成功！',
            'id' => $id,
        ];
    }


    /**
     * @param $domain_user
     * @param $input
     * @param $Goods
     * @param $gid
     * @param $num
     * @return array|false
     * 计算上级购买此商品的价格，用于计算提成
     */
    public static function SuperiorCosting($domain_user, $input, $Goods, $gid, $num)
    {
        global $date;
        $Sku = $input;
        if ($Goods['specification'] == 2) {
            $SpRule = RlueAnalysis($Goods, 1, $domain_user, true);
            $SkuData = [
                'data' => $SpRule,
                'SPU' => json_decode($Goods['specification_spu'], TRUE),
            ];
            $KeyName = [];
            $SpuIn = 0; //初始化
            $InputArr = [];
            foreach ($SkuData['SPU'] as $val) {
                $inputs = $InputArr[$SpuIn];
                foreach ($Sku as $v) {
                    if (in_array($v, $val)) {
                        $inputs = $v;
                    }
                }
                $InputArr[$SpuIn] = $inputs;
                ++$SpuIn;
            }
            foreach ($InputArr as $v) {
                $KeyName[] = $v;
            }

            $DataRule = $SkuData['data']['Parameter'][implode('`', $KeyName)];
            if (empty($DataRule)) {
                return false;
            }
            $Goods = array_merge($Goods, $DataRule);
            $pricer['level'] = $SkuData['data']['level'];
        } else {
            $pricer = Price::Get($Goods['money'], $Goods['profits'], login_data::user_grade($domain_user['id']), $Goods['gid'], $Goods['selling'], $Goods['profit_rule'], 2);
            $Goods['price'] = $pricer['price'];
            $Goods['points'] = $pricer['points'];
        }
        /**
         * 限购秒杀活动参数计算
         */
        $DB = SQL::DB();
        $Seckill = $DB->get('seckill', ['start_time', 'end_time', 'astrict', 'depreciate'], [
            'end_time[>]' => $date,
            'start_time[<]' => $date,
            'gid' => (int)$gid
        ]);
        if ($Seckill) {
            $attend = $DB->count('order', [
                'gid' => $gid,
                'addtitm[>]' => $Seckill['start_time'],
                'addtitm[<]' => $Seckill['end_time']
            ]) - 1;
            if ($attend < $Seckill['astrict']) {
                $Seckill = $Seckill['depreciate'] - 0;
                $Goods['price'] -= $Goods['price'] * ($Seckill / 100);
                $Goods['points'] -= $Goods['points'] * ($Seckill / 100);
            }
        }
        unset($Seckill);
        $points_domain = $Goods['points'] * $num;
        if ($Goods['freight'] != -1) {
            $freight = $DB->get('freight', '*', [
                'id' => (int)$Goods['freight']
            ]);
            if ($freight) {
                $price_domain = Price::Freight($freight, $input, $Goods['price'], $num);
            } else {
                $price_domain = $Goods['price'] * $num;
            }
        } else {
            $price_domain = $Goods['price'] * $num;
        }
        return [
            'code' => 1,
            'msg' => '计算成功',
            'data' => [
                'price' => $price_domain,
                'points' => $points_domain,
                'money' => $Goods['money'] * $num, //商品成本
            ]
        ];
    }

    /**
     * @param $Data //下单信息，需要包含：gid,num,data[下单信息],CouponId[购物车id,可有可无]
     * 获取商品信息【不验证下单方式是否支持，仅获取信息】
     * 基础信息+价格+库存+验证是否可以购买
     * @param $User //用户信息
     * @param $Type //是否需要验证库存
     * @return array
     */
    public static function GetProductInformation($Data, $User = false, $Type = 1)
    {
        if (!$User) {
            $User = login_data::user_data();
        }
        if (!$Data['CouponId']) {
            $Data['CouponId'] = -1;
        }
        $Verify = Buy::Verify($Data['gid'], $Data['num'], $Data['data'], $User);
        if ($Verify['code'] != 1) {
            return $Verify;
        }
        $Goods = $Verify['data'];
        $Verify = Buy::Price($Goods, $Data, $User);
        if ($Verify['code'] != 1) {
            return $Verify;
        }
        $Goods = $Verify['data'];
        $GetStock = Buy::GetStock($Data['gid'], $Data['data']);
        if ($GetStock['code'] != 1) {
            return $GetStock;
        }
        $Goods['quota'] = $GetStock['count']; //获取实时库存

        if ($Type === 1 && $Goods['quota'] < $Goods['num']) {
            return [
                'code' => -1,
                'msg' => '商品库存不足！'
            ];
        }

        return [
            'code' => 1,
            'msg' => '商品信息获取成功',
            'data' => $Goods
        ];
    }

    /**
     * @param $Goods //商品数据【里面包含价格以及完成了订单验证后的信息】
     * @param $DataBuy //里面包含：data[下单信息] num[购买份数] type[付款方式] mode[支付接口]
     * @param $Type //1=正常付款，2=无需付款[免费商品]，3=无需付款[无免费付款日志]
     * @return array
     * 创建订单扣款后发货
     */
    public static function OrderSubmit($Goods, $DataBuy, $Type)
    {
        $Order = self::Create($Goods, $DataBuy);
        if ($Order['code'] != 1) {
            return [
                'code' => -1,
                'msg' => $Order['msg'],
            ];
        }
        $Order = $Order['data'];
        //开始执行订单付款操作，如果付款成功就返回成功
        $PayRes = self::Pay($Order['order'], $Order['gid'], $Type);
        if ($PayRes['code'] != 1) {
            return [
                'code' => -1,
                'msg' => $PayRes['msg'],
            ];
        }
        //开始执行订单创建流程[数据库订单]
        $OrderNew = self::CreateOrder($Order['gid'], $Order['order'], $PayRes['payment']);
        if ($OrderNew['code'] != 1) {
            return [
                'code' => -1,
                'msg' => $OrderNew['msg'],
            ];
        }
        //订单发货
        return self::Delivery($OrderNew['data']['id']);
    }

    /**
     * 执行商品发货队列
     */
    public static function DispatchQueue()
    {
        $Path = SYSTEM_ROOT . 'extend/log/Order/Delayed/';
        $List = for_dir($Path);
        if (count($List) === 0) {
            return false;
        }
        foreach ($List as $FileName) {
            $PathFile = $Path . $FileName;
            if (!is_file($PathFile)) {
                continue;
            }
            $Json = file_get_contents($PathFile);
            @unlink($PathFile);
            if (!$Json) {
                continue;
            }
            if (!$Json = json_decode($Json, true)) {
                continue;
            }
            Order::OrderSubmit($Json['OrData'], $Json['Goods'], 1, true);
            unset($Json);
        }
        return true;
    }


    /**
     * @param $Gid //下单商品
     * @param $DataInput //下单信息，格式：num---input(多行输入框使用|分割)，数组格式
     * @param int $Type //是否启用重复订单拦截，1开启，2关闭
     * @return array
     * 批量下单
     */
    public static function BatchBuy($Gid, $DataInput, $Type = 1)
    {
        global $conf;
        $Data = [];
        if ($Type != 1) {
            $conf['OrderAstrict'] = 0;
        }
        foreach ($DataInput as $key => $v) {
            $Exp = explode('---', $v); //分隔符
            $Num = $Exp[0] - 0;
            if (empty($Exp[1])) {
                $Input = [];
            } else {
                $Input = explode('|', $Exp[1]); //下单信息之间使用|分割
            }
            $Goods = self::GetProductInformation([
                'gid' => $Gid,
                'num' => $Exp[0],
                'data' => $Input,
            ]);
            if ($Goods['code'] >= 1) {
                $Goods = $Goods['data'];
            } else {
                $Data[] = '第' . ($key + 1) . '行下单失败，' . $Goods['msg'] . '！';
                continue;
            }
            $Res = self::OrderSubmit($Goods, [
                'type' => 2,
                'data' => $Input,
                'num' => $Num,
                'mode' => 'alipay',
            ], 1);
            if (!$Res) {
                $Data[] = '第' . ($key + 1) . '行下单失败，未知错误！';
                continue;
            }
            if ($Res['code'] == -1) {
                $Data[] = '第' . ($key + 1) . '行下单失败，' . $Res['msg'] . '！';
                continue;
            }
            $Data[] = '第' . ($key + 1) . '行下单信息提交成功，订单号：' . $Res['id'] . '！';
        }
        return [
            'code' => 1,
            'msg' => '结算完成',
            'data' => $Data,
        ];
    }
}
